Elasticsearch

Facets

Les facettes sont dépréciés depuis la version 1.5 au profit d'aggregations (voir plus bas).

La recherche à facettes (ou recherche facettée, ou navigation à facettes) est une technique en recherche d'information correspondant à une méthodologie d'accès à l'information basée sur une classification à facettes. Elle donne aux utilisateurs les moyens de filtrer une collection de données en choisissant un ou plusieurs critères (les facettes). Il n'est donc pas tant question de recherche que de filtrage (une recherche brute, taxonomique, pouvant être utilisée en complément). Une classification à facettes associe à chaque donnée de l'espace de recherche un certain nombre d'axes explicites de filtrage, par exemple des mots clés issus d'une analyse texte, des métadonnées stockées dans une base de données, etc. On trouve par exemple des recherches à facettes basées sur des catégories sur de nombreux sites de e-commerce.

Facette sur les term

{
    "query": {
        "match_all": {}
    },
    "facets": {
        "tags": {
            "terms": {
                "field": "nom",
                # Le nombre de facette retournés
                "size":"10"
            }
        }
    }
}

La facette va nous retourner plusieurs résultats :

"_type": "terms", # Type de facette
"missing": 66113, # Nb de résultat sans le term
"total": 0, # Le nb de résultat compté
"other": 0, # Le nb de facette compté mais pas retourné
"terms": [ ] # La liste des facettes

Déprécié depuis la version 1.5 au profit des aggregations.

Plus d'infos sur les facettes

Aggregations

Il existe plusieurs type d'aggregations, certaines restes encore experimentales et risquent d'être supprimés dans des releases futures. Toute ne sont pas abordés ici, pour plus d'informations

  • Min aggreg : qui permettent de retourner la valeur minimum d'un champ numérique
    {
        "aggs" : {
            "min_price" : { "min" : { "field" : "price" } }
        }
    }
  • max aggreg : permet de rretourner la valeur maximale d'un champ numérique
    {
     "aggs" : {
         "max_price" : { "max" : { "field" : "price" } }
     }
    }
    
  • sum aggreg : permet de sommer des valeurs numériques, provenant d'un champ ou qui ont pu être générées
    {
      "query" : {
          "filtered" : {
              "query" : { "match_all" : {}},
              "filter" : {
                  "range" : { "timestamp" : { "from" : "now/1d+9.5h", "to" : "now/1d+16h" }}
              }
          }
      },
      "aggs" : {
          "intraday_return" : { "sum" : { "field" : "change" } }
      }
    }
    
  • avg aggreg : permet de faire une moyenne d'un champ numérique
    {
      "aggs" : {
          "avg_grade" : { "avg" : { "field" : "grade" } }
      }
    }
    
  • stats aggreg : Wrapper permettant d'éxecuter directement les aggregations count,mint,max,avg et sum.
{
    "aggs" : {
        "grades_stats" : { "stats" : { "field" : "grade" } }
    }
}

{
    ...

    "aggregations": {
        "grades_stats": {
            "count": 6,
            "min": 60,
            "max": 98,
            "avg": 78.5,
            "sum": 471
        }
    }
}

On a également la possiblité de faire des stats un peu plus poussée à l'aide de l'aggregation extended_stat (en obtenant la variance, la déviance, etc).

{
    "aggs" : {
        "grades_stats" : { "extended_stats" : { "field" : "grade" } }
    }
}
{
    ...

    "aggregations": {
        "grade_stats": {
           "count": 9,
           "min": 72,
           "max": 99,
           "avg": 86,
           "sum": 774,
           "sum_of_squares": 67028,
           "variance": 51.55555555555556,
           "std_deviation": 7.180219742846005,
           "std_deviation_bounds": {
            "upper": 100.36043948569201,
            "lower": 71.63956051430799
           }
        }
    }
}
  • Centile aggreg : Permet d'éxecuter des centile sur les champ numériques
    {
      "aggs" : {
          "load_time_outlier" : {
              "percentiles" : {
                  "field" : "load_time" 
              }
          }
      }
    }
    
  • Cardinality aggreg : équivalent d'un count distinct en MySQL.
    {
      "aggs" : {
          "author_count" : {
              "cardinality" : {
                  "field" : "author"
              }
          }
      }
    }
    
  • geo_bound aggreg : Une aggregation donnant une métrique qui calcule la zone contenant tous les point pour un champ de type géométrique.
    {
      "query" : {
          "match" : { "business_type" : "shop" }
      },
      "aggs" : {
          "viewport" : {
              "geo_bounds" : {
                  # Le champ qui va permettre d'obtenir la zone de délimitation
                  "field" : "location", 
                  "wrap_longitude" : true 
              }
          }
      }
    }
    
  • top hit aggreg : Aggrégation assez intéressante car elle permet de faire une aggregation d'aggrégation. Chaque élement que va renvoyer une aggregation va pouvoir être réaggregé à un niveau inférieur. Dans mon exemple, je regroupe les document par tag et pour chaque tag récupère la dernière question active.
    {
      "aggs": {
          "top-tags": {
              "terms": {
                  "field": "tags",
                  "size": 3
              },
              "aggs": {
                  "top_tag_hits": {
                      "top_hits": {
                          "sort": [
                              {
                                  "last_activity_date": {
                                      "order": "desc"
                                  }
                              }
                          ],
                          "_source": {
                              "include": [
                                  "title"
                              ]
                          },
                          "size" : 1
                      }
                  }
              }
          }
      }
    }
    # et le résultat 
    "aggregations": {
    "top-tags": {
       "buckets": [
          {
             "key": "windows-7",
             "doc_count": 25365,
             "top_tags_hits": {
                "hits": {
                   "total": 25365,
                   "max_score": 1,
                   "hits": [
                      {
                         "_index": "stack",
                         "_type": "question",
                         "_id": "602679",
                         "_score": 1,
                         "_source": {
                            "title": "Windows port opening"
                         },
                         "sort": [
                            1370143231177
                         ]
                      }
                   ]
                }
             }
          },
          {
             "key": "linux",
             "doc_count": 18342,
             "top_tags_hits": {
                "hits": {
                   "total": 18342,
                   "max_score": 1,
                   "hits": [
                      {
                         "_index": "stack",
                         "_type": "question",
                         "_id": "602672",
                         "_score": 1,
                         "_source": {
                            "title": "Ubuntu RFID Screensaver lock-unlock"
                         },
                         "sort": [
                            1370143379747
                         ]
                      }
                   ]
                }
             }
          },
          {
             "key": "windows",
             "doc_count": 18119,
             "top_tags_hits": {
                "hits": {
                   "total": 18119,
                   "max_score": 1,
                   "hits": [
                      {
                         "_index": "stack",
                         "_type": "question",
                         "_id": "602678",
                         "_score": 1,
                         "_source": {
                            "title": "If I change my computers date / time, what could be affected?"
                         },
                         "sort": [
                            1370142868283
                         ]
                      }
                   ]
                }
             }
          }
       ]
    }
    }
    
  • filter aggreg : Permet d'appliquer un filtre sur une série de document déjà aggregé par une autre aggreg
{
    "aggs" : {
        "in_stock_products" : {
            "filter" : { "range" : { "stock" : { "gt" : 0 } } },
            "aggs" : {
                "avg_price" : { "avg" : { "field" : "price" } }
            }
        }
    }
}

{
    ...

    "aggs" : {
        "in_stock_products" : {
            "doc_count" : 100,
            "avg_price" : { "value" : 56.3 }
        }
    }
}
  • on peut également appliquer plusieurs filtres.
    {
    "aggs" : {
      "messages" : {
        "filters" : {
          "filters" : {
            "errors" :   { "term" : { "body" : "error"   }},
            "warnings" : { "term" : { "body" : "warning" }}
          }
        },
        "aggs" : {
          "monthly" : {
            "histogram" : {
              "field" : "timestamp",
              "interval" : "1M"
            }
          }
        }
      }
    }
    }
    
  • Nested aggreg : faire des aggregation sur des champs imbriqués, par exemple ici je désire faire une aggregation sur le label d'un champ imbriqué tag (contenant un array d'objet).
    {
      "query": {
          "match_all":{}
      },
      "aggs": {
          "tags": {
              "nested": {
                  "path":"tags"
              },
              "aggs": {
                  "abel":{
                      "terms": { "field":"tags.label"  }
                  }
              }
          }
      }
    }
    
  • Terms : permet de faire des aggregs sur des terms de manière très simple
{
    "aggs" : {
        "genders" : {
            "terms" : { "field" : "gender" }
        }
    }
}
  • Histogram aggreg : Applicable sur des champs numérique, exemple
# Créer moi un histogramme des articles ayant un prix sur un interval de 50
{
    "aggs" : {
        "prices" : {
            "histogram" : {
                "field" : "price",
                "interval" : 50
            }
        }
    }
}

Résultat 
...

{
    "aggregations": {
        "prices" : {
            "buckets": [

                {
                    "key": 0,
                    "doc_count": 2
                },
                # 4 documents au prix de 50
                {
                    "key": 50,
                    "doc_count": 4
                },
                {
                    "key": 150,
                    "doc_count": 3
                }
            ]
        }
    }
}

On constate ici que 100 n'est pas affiché (probablement du au fait qu'aucun résultat est retourné), pour palier à ça il est nécessaire d'ajouter ce paramètre à la requête après interval : "min_doc_count" : 0